/**
 * \file texture.h
 * Texture Module
 *
 * Provides:
 * 	- basic texture class
 *  - Image textures (square and rectangular)
 **
 * Author: Sean Micklethwaite
 **
 * License... etc.
 **/

#ifndef __textureH__
#define __textureH__

#include "data.h"
#include "pixeltype.h"

namespace WtfEngine
{
	/**
	 * Texture Class, a basic representation for the simplest form of a
	 * a texture. A texture can be either square or rectangular.
	 *
	 * \sa 	TextureImage
	 */
	class Texture : public DataObject
	{
	protected:
		GLuint		mHandle;
		iVector2D	mDim;

		/// Determines whether the texture is rectangular, default is true
		bool		rectangular;

	public:
		Texture(const StringPool::Entry& sName);

		virtual ~Texture();

		/// Reads the texture image from a file
		virtual void Read(const String& sFile, bool forceRect = false);
		/// Writes the image to a file. Type is implied by
		/// file extension.
		virtual void Write(const String& sFile);

		/// Create the texture from a pixel buffer
		virtual void Create(const WtfGraphics::IPixelBuffer::tRef& rPixels, const iVector2D& vDim);
		

		/// Draws the (2D) texture at the current position
		void Draw(const iVector2D& vSize);
		/// Draws to specified screen
		void DrawToScreen(const IScreen::tRef& rScreen);

		// gfx mem operations
		void Bind(int texNum = 0);
		void Release(int texNum = 0);

		/// returns raw size in bytes
		unsigned GetRawSize() const {
			return mDim.x() * mDim.y() * sizeof(tScalar) * 4;
		};

		/// returns width in pixels
		int getWidth() const { return mDim[0]; };

		/// returns height in pixels
		int getHeight() const { return mDim[1]; };

		const iVector2D& getSize() const { return mDim; };

		/// returns true if the texture is rectangular
		bool isRectangular() const { return rectangular; }

		inline fVector2D ConvertNormalCoordinateToImage(const fVector2D& vCoord) const {
			fVector2D vNormalized(vCoord - fVector2D(floor(vCoord[0]),floor(vCoord[1])));
			return fVector2D(vNormalized[0] * (float)getSize()[0], vNormalized[1] * (float)getSize()[1]);
		};

		inline fVector2D ConvertNormalCoordinate(const fVector2D& vCoord) const {
			return isRectangular() ? ConvertNormalCoordinateToImage(vCoord) : vCoord;
		};

		inline void ConvertNormalCoordinates(std::vector<fVector2D>& vvCoord) const {
			if(isRectangular()) {
				for(std::vector<fVector2D>::iterator i = vvCoord.begin(); i != vvCoord.end(); i++) {
					*i = ConvertNormalCoordinateToImage(*i);
				};
			};
		};

		/// Interface to data manager
		static IDataObject * Load(const StringPool::Entry& sImageFile);
		DATA_LOADABLE(Texture, sizeof(Texture) + GetRawSize());
	};

	class FBOTexture : public virtual IScreen, public Texture
	{
	public:
		/// Pixel type of FBOs is always RGBA 32-bit float.
		typedef WtfGraphics::PixelType::tRGBA32f	tPixels;

	private:
		static GLuint	gFBO;

		GLuint			mDepthBuf, mStencilBuf;

	public:
		FBOTexture();
		~FBOTexture();

		void Create(int w, int h);
		inline void Create(const iVector2D& vDim) {
			Create(vDim[0], vDim[1]);
		};

		void Write(const String& sFile);

		void Write(const tPixels::tRef& rPixels);
		void Read(const tPixels::tRef& rPixels);

		void Activate();
		void Deactivate();

		iVector2D getSize() const {
			return Texture::getSize();
		};

		typedef GcReference<FBOTexture>	tRef;
	};

	/**
	 * Texture Subclass for loading images as textures.
	 * @deprecated
	 */
	class TextureImage : public Texture
	{
	private:
		bool forceRect;			///< Texture forced to be rectangular?
	public:
		TextureImage(const StringPool::Entry& sName) : Texture(sName) {
			this->forceRect   = false;
		};

		DATA_LOADABLE(TextureImage, sizeof(TextureImage) + GetRawSize());
	};
};

#endif
